package chan.project.service.impl;

import chan.project.exception.BusinessException;
import chan.project.model.dto.file.UploadPictureResult;
import chan.project.model.dto.picture.PictureQueryRequest;
import chan.project.model.dto.picture.PictureReviewRequest;
import chan.project.model.dto.picture.PictureUploadRequest;
import chan.project.model.enums.ReviewStatusEnum;
import chan.project.template.FilePictureUpload;
import chan.project.template.UrlPictureUpload;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import chan.project.common.ErrorCode;
import chan.project.exception.ThrowUtils;
import chan.project.mapper.PictureMapper;
import chan.project.model.entity.Picture;
import chan.project.model.entity.User;
import chan.project.model.vo.PictureVO;
import chan.project.model.vo.UserVO;
import chan.project.service.PictureService;
import chan.project.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 图片上传服务实现
 *
 * @author <a href="https://github.com/kavansp">kavansp</a>
 * @from <a href="https://www.code-nav.cn">编程导航学习圈</a>
 */
@Service
@Slf4j
public class PictureServiceImpl extends ServiceImpl<PictureMapper, Picture> implements PictureService {

    @Resource
    private UserService userService;

    @Resource
    private FilePictureUpload filePictureUpload;

    @Resource
    private UrlPictureUpload urlPictureUpload;

    /**
     * 校验数据
     *
     * @param picture
     * @param add      对创建的数据进行校验
     */
    @Override
    public void validPicture(Picture picture, boolean add) {
        ThrowUtils.throwIf(picture == null, ErrorCode.PARAMS_ERROR);
        // 从对象中取值
        Long id = picture.getId();
        String url = picture.getUrl();
        String introduction = picture.getIntroduction();
        // 修改数据时，id 不能为空，有参数则校验
        if(add) {
            ThrowUtils.throwIf(ObjUtil.isNull(id), ErrorCode.PARAMS_ERROR, "id 不能为空");
            if (StrUtil.isNotBlank(url)) {
                ThrowUtils.throwIf(url.length() > 1024, ErrorCode.PARAMS_ERROR, "url 过长");
            }
            if (StrUtil.isNotBlank(introduction)) {
                ThrowUtils.throwIf(introduction.length() > 800, ErrorCode.PARAMS_ERROR, "简介过长");
            }
        }
    }

    /**
     * 获取查询条件
     *
     * @param pictureQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<Picture> getQueryWrapper(PictureQueryRequest pictureQueryRequest) {
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        if (pictureQueryRequest == null) {
            return queryWrapper;
        }
        // 从对象中取值
        Long id = pictureQueryRequest.getId();
        String name = pictureQueryRequest.getName();
        String introduction = pictureQueryRequest.getIntroduction();
        String category = pictureQueryRequest.getCategory();
        List<String> tags = pictureQueryRequest.getTags();
        Long picSize = pictureQueryRequest.getPicSize();
        Integer picWidth = pictureQueryRequest.getPicWidth();
        Integer picHeight = pictureQueryRequest.getPicHeight();
        Double picScale = pictureQueryRequest.getPicScale();
        String picFormat = pictureQueryRequest.getPicFormat();
        String searchText = pictureQueryRequest.getSearchText();
        Long userId = pictureQueryRequest.getUserId();
        Integer reviewStatus = pictureQueryRequest.getReviewStatus();
        String reviewMessage = pictureQueryRequest.getReviewMessage();
        Long reviewId = pictureQueryRequest.getReviewId();
        Date reviewTime = pictureQueryRequest.getReviewTime();
        int current = pictureQueryRequest.getCurrent();
        int pageSize = pictureQueryRequest.getPageSize();
        String sortField = pictureQueryRequest.getSortField();
        String sortOrder = pictureQueryRequest.getSortOrder();


        // 从多字段中搜索
        if (StrUtil.isNotBlank(searchText)) {
            // 需要拼接查询条件
            queryWrapper.and(qw -> qw.like("name", searchText)
                    .or()
                    .like("introduction", searchText)
            );
        }
        queryWrapper.like(StrUtil.isNotBlank(name), "name", name);
        queryWrapper.like(StrUtil.isNotBlank(introduction), "introduction", introduction);
        queryWrapper.like(StrUtil.isNotBlank(picFormat), "picFormat", picFormat);
        queryWrapper.like(StrUtil.isNotBlank(reviewMessage), "reviewMessage", reviewMessage);
        queryWrapper.eq(ObjUtil.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjUtil.isNotEmpty(userId), "userId", userId);
        queryWrapper.eq(StrUtil.isNotBlank(category), "category", category);
        queryWrapper.eq(ObjUtil.isNotEmpty(picWidth), "picWidth", picWidth);
        queryWrapper.eq(ObjUtil.isNotEmpty(picHeight), "picHeight", picHeight);
        queryWrapper.eq(ObjUtil.isNotEmpty(picSize), "picSize", picSize);
        queryWrapper.eq(ObjUtil.isNotEmpty(picScale), "picScale", picScale);
        queryWrapper.eq(ObjUtil.isNotEmpty(reviewStatus), "reviewStatus", reviewStatus);
        queryWrapper.eq(ObjUtil.isNotEmpty(reviewId), "reviewId", reviewId);

        // JSON 数组查询
        if (CollUtil.isNotEmpty(tags)) {
            for (String tag : tags) {
                queryWrapper.like("tags", "\"" + tag + "\"");
            }
        }
        // 排序
        queryWrapper.orderBy(StrUtil.isNotEmpty(sortField), sortOrder.equals("ascend"), sortField);
        return queryWrapper;
    }


    /**
     * 获取图片上传封装
     *
     * @param picture
     * @param request
     * @return
     */
    @Override
    public PictureVO getPictureVO(Picture picture, HttpServletRequest request) {
        // 对象转封装类
        PictureVO pictureVO = PictureVO.objToVo(picture);
        // region 可选
        // 1. 关联查询用户信息
        Long userId = picture.getUserId();
        User user = null;
        if (userId != null && userId > 0) {
            user = userService.getById(userId);
        }
        UserVO userVO = userService.getUserVO(user);
        pictureVO.setUser(userVO);
        // 2. 已登录，获取用户点赞、收藏状态
        long pictureId = picture.getId();
        User loginUser = userService.getLoginUserPermitNull(request);
        if (loginUser != null) {
            // 获取点赞
        }
        // endregion

        return pictureVO;
    }

    /**
     * 图片上传或者修改（如果有id就是修改，没有就是添加）
     * @param multipartFile
     * @param pictureUploadRequest
     * @param loginUser
     * @return
     */
    @Override
    public PictureVO uploadPicture(MultipartFile multipartFile, PictureUploadRequest pictureUploadRequest, User loginUser) {
        ThrowUtils.throwIf(pictureUploadRequest == null,ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(loginUser == null,ErrorCode.PARAMS_ERROR);
        Long id = pictureUploadRequest.getId();
        Picture picture = new Picture();
        if(id != null){
            Picture oldPicture = this.getById(id);
            ThrowUtils.throwIf(oldPicture == null,ErrorCode.NOT_FOUND_ERROR,"查询的图片不存在");
            picture.setId(id);
            ThrowUtils.throwIf(!Objects.equals(oldPicture.getUserId(), loginUser.getId()) || !userService.isAdmin(loginUser)
                    ,ErrorCode.NO_AUTH_ERROR,"权限不足");
        }
        String filePath = String.format("public/%s", loginUser.getId());
        filePictureUpload.validFile(multipartFile);
        UploadPictureResult uploadPictureResult = filePictureUpload.uploadPicture(multipartFile, filePath);
        //将cos存储的图片存储到数据库中
        picture.setUrl(uploadPictureResult.getUrl());
        picture.setName(uploadPictureResult.getPicName());
        picture.setPicSize(uploadPictureResult.getPicSize());
        picture.setPicWidth(uploadPictureResult.getPicWidth());
        picture.setPicHeight(uploadPictureResult.getPicHeight());
        picture.setPicScale(uploadPictureResult.getPicScale());
        picture.setPicFormat(uploadPictureResult.getPicFormat());
        picture.setUserId(loginUser.getId());
        //id不为空，表示更新
        if(id != null){
            picture.setId(id);
            picture.setEditTime(new Date());
        }
        fillReviewMessage(picture,loginUser);
        boolean save = this.saveOrUpdate(picture);
        ThrowUtils.throwIf(!save,ErrorCode.OPERATION_ERROR,"保存数据失败");
        return PictureVO.objToVo(picture);
    }

    @Override
    public PictureVO uploadPictureByUrl(String url, PictureUploadRequest pictureUploadRequest, User loginUser) {
        ThrowUtils.throwIf(url == null,ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(pictureUploadRequest == null,ErrorCode.PARAMS_ERROR);
        Long id = pictureUploadRequest.getId();
        Picture picture = new Picture();
        if(id != null){
            Picture oldPicture = this.getById(id);
            ThrowUtils.throwIf(oldPicture == null,ErrorCode.NOT_FOUND_ERROR,"查询的图片不存在");
            picture.setId(id);
            ThrowUtils.throwIf(!Objects.equals(oldPicture.getUserId(), loginUser.getId()) || !userService.isAdmin(loginUser)
                    ,ErrorCode.NO_AUTH_ERROR,"权限不足");
        }
        String filePath = String.format("public/%s", loginUser.getId());
        urlPictureUpload.validFile(url);
        UploadPictureResult uploadPictureResult = urlPictureUpload.uploadPicture(url, filePath);
        //将cos存储的图片存储到数据库中
        picture.setUrl(uploadPictureResult.getUrl());
        picture.setName(uploadPictureResult.getPicName());
        picture.setPicSize(uploadPictureResult.getPicSize());
        picture.setPicWidth(uploadPictureResult.getPicWidth());
        picture.setPicHeight(uploadPictureResult.getPicHeight());
        picture.setPicScale(uploadPictureResult.getPicScale());
        picture.setPicFormat(uploadPictureResult.getPicFormat());
        picture.setUserId(loginUser.getId());
        //id不为空，表示更新
        if(id != null){
            picture.setId(id);
            picture.setEditTime(new Date());
        }
        fillReviewMessage(picture,loginUser);
        boolean save = this.saveOrUpdate(picture);
        ThrowUtils.throwIf(!save,ErrorCode.OPERATION_ERROR,"保存数据失败");
        return PictureVO.objToVo(picture);
    }

    /**
     * 分页获取图片上传封装
     *
     * @param picturePage
     * @param request
     * @return
     */
    @Override
    public Page<PictureVO> getPictureVOPage(Page<Picture> picturePage, HttpServletRequest request) {
        List<Picture> pictureList = picturePage.getRecords();
        Page<PictureVO> pictureVOPage = new Page<>(picturePage.getCurrent(), picturePage.getSize(), picturePage.getTotal());
        if (CollUtil.isEmpty(pictureList)) {
            return pictureVOPage;
        }
        // 对象列表 => 封装对象列表
        List<PictureVO> pictureVOList = pictureList.stream().map(picture -> {
            return PictureVO.objToVo(picture);
        }).collect(Collectors.toList());

        // region 可选
        // 1. 关联查询用户信息
        Set<Long> userIdSet = pictureList.stream().map(Picture::getUserId).collect(Collectors.toSet());
        Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));
        // 填充信息
        pictureVOList.forEach(pictureVO -> {
            Long userId = pictureVO.getUserId();
            User user = null;
            if (userIdUserListMap.containsKey(userId)) {
                user = userIdUserListMap.get(userId).get(0);
            }
            pictureVO.setUser(userService.getUserVO(user));
        });
        // endregion

        pictureVOPage.setRecords(pictureVOList);
        return pictureVOPage;
    }

    @Override
    public void doPictureReview(PictureReviewRequest pictureReviewRequest,User loginUser) {
        Long id = pictureReviewRequest.getId();
        Integer reviewStatus = pictureReviewRequest.getReviewStatus();
        ReviewStatusEnum reviewStatusEnum = ReviewStatusEnum.getReviewStatusEnum(reviewStatus);
        String reviewMessage = pictureReviewRequest.getReviewMessage();
        if(id == null || reviewStatusEnum == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Picture picture = this.getById(id);
        ThrowUtils.throwIf(ObjectUtil.isEmpty(picture), ErrorCode.NOT_FOUND_ERROR);
        if(Objects.equals(picture.getReviewStatus(), reviewStatusEnum.getValue())){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"请勿重复审核");
        }
        picture.setReviewStatus(reviewStatus);
        picture.setReviewMessage(reviewMessage);
        picture.setReviewId(loginUser.getId());
        boolean b = this.updateById(picture);
        ThrowUtils.throwIf(!b,ErrorCode.OPERATION_ERROR,"审核操作失败");
    }

    /**
     * 自动填充图片信息（管理员创建的图片自动过审）
     * @param picture
     * @param loginUser
     * @return
     */
    @Override
    public Picture fillReviewMessage(Picture picture, User loginUser){
        if(userService.isAdmin(loginUser)){
            picture.setReviewStatus(ReviewStatusEnum.APPROVED.getValue());
            picture.setReviewMessage("管理员创建图片自动过审");
            picture.setReviewTime(new Date());
            picture.setEditTime(new Date());
        }else {
            picture.setReviewStatus(ReviewStatusEnum.PENDING_REVIEW.getValue());
        }
        return picture;
    }


}
